package com.cnebula.openapi.auth.service.impl;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

import com.cnebula.openapi.auth.exception.SignException;
import com.cnebula.openapi.auth.exception.SignExpireException;
import com.cnebula.openapi.auth.exception.SignIllegalException;
import com.cnebula.openapi.auth.service.SignService;
import com.cnebula.openapi.auth.util.MD5Util;

import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;

public class SignServiceImpl implements SignService {

	private static final long DURATION = 60 * 10000;
	
	private static final Logger log = LoggerFactory.getLogger(SignServiceImpl.class);
	
	@Override
	public String sign(Map<String, String> params, String secret) throws SignException{
		StringBuilder raw = new StringBuilder(secret);
		raw.append(this.signStr(params));
		raw.append(secret);
		String str = "";
		try {
			str = MD5Util.md5(raw.toString());
		} catch (NoSuchAlgorithmException | UnsupportedEncodingException e1) {
			log.error("sign create fail", e1);
			throw new SignException(e1);
		}
		return str;
	}
	@Override
	public Integer check(Map<String, String> params, String secret, String signature) throws SignException, SignIllegalException {
		Integer rst = 200;
		String sign = this.sign(params, secret);
		if(!sign.equals(signature)) {
			throw new SignIllegalException();
		}
		return rst;
	}

	@Override
	public Integer check(Map<String, String> params, String secret, long timestamp, String signature) throws SignException, SignIllegalException, SignExpireException {
		Integer rst = 200;
		String sign = this.sign(params, secret);
		long current = System.currentTimeMillis();
		if(!sign.equals(signature)) {
			throw new SignIllegalException();
		}else if(current - timestamp > DURATION) {
			// 签名已过期
			throw new SignExpireException();
		}
		return rst;
	}
	
	private String signStr(Map<String, String> params){
		StringBuilder raw = new StringBuilder();
		params.entrySet().stream().sorted(Map.Entry.<String,String>comparingByKey()).forEachOrdered(e -> {
			raw.append(e.getKey()).append(e.getValue());
		});
		return raw.toString();
	}
	
}
